﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;

namespace $projectname$.Repositories.Base
{

    /// <summary>
    /// Interface definition for a generic repository.
    /// </summary>
    /// <typeparam name="T">Type of entity the repository will interact with.</typeparam>
    /// <remarks>
    /// Refer http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application.
    /// Refer http://blog.magnusmontin.net/2013/05/30/generic-dal-using-entity-framework/.
    /// </remarks>
    public interface IGenericDataRepository<T> : IDisposable where T : class
    {

        #region Properties

        /// <summary>
        /// Gets or sets a value indicating whether to automatically save changes as part of action methods (Add, Modify, Remove).
        /// </summary>
        bool AutoSave { get; set; }

        #endregion

        #region Methods

        /// <summary>
        /// Returns a list of items from the repository matching the provided criteria.
        /// </summary>
        /// <param name="filter">Filter criteria.</param>
        /// <param name="navigationProperties">Additional navigation properties to be included in the results.</param>
        /// <returns>List of matching items.</returns>
        List<T> List(Expression<Func<T, bool>> filter = null, params Expression<Func<T, object>>[] navigationProperties);

        /// <summary>
        /// Returns a single item from the repository matching the provided criteria.
        /// </summary>
        /// <param name="filter">Filter criteria.</param>
        /// <param name="navigationProperties">Additional navigation properties to be included in the results.</param>
        /// <returns>Matching item, or null if no items match.</returns>
        T Get(Expression<Func<T, bool>> filter, params Expression<Func<T, object>>[] navigationProperties);

        /// <summary>
        /// Adds an item to the repository.
        /// </summary>
        /// <param name="item">Item to be added.</param>
        /// <remarks>
        /// If the AutoSave property is true, adds the item and saves it automatically.
        /// If the AutoSave property is false, adds the item and waits for the Save method to be called explicitly.
        /// </remarks>
        void Add(T item);

        /// <summary>
        /// Modifies an item in the repository.
        /// </summary>
        /// <param name="item">Modified item.</param>
        /// <remarks>
        /// If the AutoSave property is true, modifies the item and saves it automatically.
        /// If the AutoSave property is false, modifies the item and waits for the Save method to be called explicitly.
        /// </remarks>
        void Modify(T item);

        /// <summary>
        /// Removes an item from the repository.
        /// </summary>
        /// <param name="item">Item to be removed.</param>
        /// <remarks>
        /// If the AutoSave property is true, removes the item and saves the removal automatically.
        /// If the AutoSave property is false, removes the item and waits for the Save method to be called explicitly.
        /// </remarks>
        void Remove(T item);

        /// <summary>
        /// Saves changes from the repository to the underlying persistence store.
        /// </summary>
        void Save();

        #endregion

    }

}
